package cn.supermaster.management.core.component;

import cn.supermaster.management.common.constant.MessageConstant;
import cn.supermaster.management.common.utils.*;
import cn.supermaster.management.system.service.ISystemUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import cn.supermaster.management.common.constant.Constants;
import cn.supermaster.management.common.constant.ShiroConstant;
import cn.supermaster.management.common.constant.UserConstant;
import cn.supermaster.management.common.domain.SystemUser;
import cn.supermaster.management.common.enums.UserStatus;
import cn.supermaster.management.common.exception.user.CaptchaException;
import cn.supermaster.management.common.exception.user.UserBlockedException;
import cn.supermaster.management.common.exception.user.UserDeleteException;
import cn.supermaster.management.common.exception.user.UserNotExistsException;
import cn.supermaster.management.common.exception.user.UserPasswordNotMatchException;
import cn.supermaster.management.core.manager.AsynchronousManager;
import cn.supermaster.management.core.manager.AsynchronousFactory;

/**
 * All rights Reserved, Designed By www.super-bytecode.com
 *
 * @ProjectName: supermaster-management
 * @Package: cn.supermaster.management.core.realm
 * @ClassName: SystemLoginService
 * @Description: [系统登录管理器]
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2021/1/10 22:23
 * @Version: V1.0
 * @Copyright: 2021 www.super-bytecode.comn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Component
public class LoginManager {

    @Autowired
    private PasswordManager passwordService;

    @Autowired
    private ISystemUserService userService;

    /**
     * @Description: [登录]
     * <p></P>
     * @Title: login
     * @Author: Lance Ting
     * @Date: 2021-01-10
     * @Param: username 用户名
     * @Param: password 密码
     * @Return: cn.supermaster.management.common.domain.SystemUser
     */
    public SystemUser login(String username, String password) {

        // 校验系统登录的用户名和密码
        doCheckUsernameAndPassword(username, password);

        // 查询用户信息
        SystemUser user = userService.selectUserByuserName(username);

        // 校验用户信息有效性
        doCheckUserEffective(user, username);

        // 密码有效性校验
        passwordService.checkPasswordEffective(user, password);

        // 用户登录认证成功日志记录
        doRecordLoginInformation(username, Constants.LOGIN_SUCCESS, MessageConstant.USER_ACCESS_SUCCESS);

        // 更新用户最后一次登录时间和地址
        recordLoginInfo(user);

        return user;
    }

    /**
     * @Description: [校验用户信息有效性]
     * <p></P>
     * @Title: doCheckUserEffective
     * @Author: Lance Ting
     * @Date: 2021-01-10
     * @Param: user 用户对象
     * @Param: username 用户名
     * @Return: void
     */
    private void doCheckUserEffective(SystemUser user, String username) {
        String failStatus = Constants.LOGIN_FAIL;
        // 用户不存在
        if (user == null) {
            doRecordLoginInformation(username, failStatus, MessageConstant.USER_NOT_EXISTS);
            throw new UserNotExistsException();
        }
        // 用户已删除
        if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            doRecordLoginInformation(username, failStatus, MessageConstant.USER_DELETE);
            throw new UserDeleteException();
        }
        // 用户无效
        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            doRecordLoginInformation(username, failStatus, MessageConstant.USER_DISABLE);
            throw new UserBlockedException();
        }
    }

    /**
     * @Description: [校验系统登录的用户名和密码]
     * <p></P>
     * @Title: doCheckUsernameAndPassword
     * @Author: Lance Ting
     * @Date: 2021-01-10
     * @Param: username 用户名称
     * @Param: password 密码
     * @Return: void
     */
    private void doCheckUsernameAndPassword(String username, String password) {

        String captcha = ShiroConstant.CURRENT_CAPTCHA;// 验证码常量
        String failStatus = Constants.LOGIN_FAIL;// 系统登录失败状态

        int passwordMinSize = UserConstant.PASSWORD_MIN_LENGTH;//密码范围最小阈值
        int passwordMaxSize = UserConstant.PASSWORD_MIN_LENGTH;//密码范围最大阈值
        int usernameMinSize = UserConstant.USERNAME_MIN_LENGTH;//用户名范围最小值
        int usernameMaxSize = UserConstant.USERNAME_MAX_LENGTH;//用户名范围最大值
        // 验证码校验
        Object currentCaptcha = ServletUtils.getRequest().getAttribute(captcha);
        if (ShiroConstant.CAPTCHA_ERROR.equals(currentCaptcha)) {
            doRecordLoginInformation(username, failStatus, MessageConstant.CAPTCHA_NO_MATCH);
            throw new CaptchaException();
        }

        // 用户名或密码为空 错误
        if (CheckUtils.checkAnyParametricEmpty(username, password)) {
            doRecordLoginInformation(username, failStatus, MessageConstant.NOT_NULL);
            throw new UserNotExistsException();
        }
        // 密码如果不在指定范围内 错误
        int passwordSize = password.length();
        if (!CheckUtils.checkDigitalScope(passwordMinSize, passwordSize, passwordMaxSize)) {
            doRecordLoginInformation(username, failStatus, MessageConstant.PASSWORD_NO_MATCH);
            throw new UserPasswordNotMatchException();
        }

        // 用户名不在指定范围内 错误
        int usernameSize = username.length();
        if (!CheckUtils.checkDigitalScope(usernameMinSize, usernameSize, usernameMaxSize)) {
            doRecordLoginInformation(username, failStatus, MessageConstant.PASSWORD_NO_MATCH);
            throw new UserPasswordNotMatchException();
        }
    }

    /**
     * @Description: [记录登录信息]
     * <p></P>
     * @Title: doRecordLoginInformation
     * @Author: Lance Ting
     * @Date: 2021-01-10
     * @Param: username 用户名称
     * @Param: status 登录状态
     * @Param: message 信息
     * @Return: void
     */
    private void doRecordLoginInformation(String username, String status, String message) {
        String convertMessage = MessageUtils.message(message);// 转换后的信息
        // 记录操作日志
        AsynchronousManager.manager().execute(AsynchronousFactory.recordLoginInformation(username, status, convertMessage));
    }


    /**
     * 记录登录信息
     */
    public void recordLoginInfo(SystemUser user) {
        user.setLoginIp(ShiroUtils.getIp());
        user.setLoginDate(DateUtils.getNowDate());
        userService.updateUserInfo(user);
    }
}
